﻿using System;
using System.Windows.Data;

namespace Notoric.ViewModel.Converters
{
    /// <summary>
    /// Implements conversion from a <see cref="double"/> value in centimeters
    /// into a <see cref="double"/> value in device-independent pixels and back.
    /// </summary>
    [ValueConversion(typeof(double), typeof(double))]
    public class LengthConverter : IValueConverter
    {
        #region IValueConverter Members

        /// <summary>
        /// Converts a value.
        /// </summary>
        /// <param name="value">The value produced by the binding source.</param>
        /// <param name="targetType">The type of the binding target property.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>A converted value. If the method returns <see langword="null"/>, the valid null value is used.</returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double val = (double)value;
            if (Double.IsNaN(val))
                return Double.NaN;

            if (SwitchConversionDirection)
                return val / cmToPx;

            return val * cmToPx;
        }

        /// <summary>
        /// Converts a value.
        /// </summary>
        /// <param name="value">The value that is produced by the binding target.</param>
        /// <param name="targetType">The type to convert to.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>A converted value. If the method returns <see langword="null"/>, the valid null value is used.</returns>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double val = (double)value;
            if (Double.IsNaN(val))
                return Double.NaN;

            if (SwitchConversionDirection)
                return val * cmToPx;

            return val / cmToPx;
        }

        #endregion

        /// <summary>
        /// Gets or sets the value indicating whether to switch the conversion direction.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Boolean"/>
        /// </para>
        /// <para>
        /// Indicates whether to switch the conversion direction.
        /// If the direction is switched, a call to <see cref="Convert"/>
        /// will result in a call to <see cref="ConvertBack"/> et vice versa.
        /// </para>
        /// </value>
        public bool SwitchConversionDirection
        {
            get;
            set;
        }

        /// <summary>
        /// 1cm = (96 / 2.54)px
        /// </summary>
        private const double cmToPx = 96 / 2.54;
    }
}
